﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using SvgViewer.Core;
using SvgViewer.Utilities;

namespace SvgViewer.Entities;

/// <summary>
/// 导出图像属性
/// </summary>
public class ExportProperty : NotifyPropertyBase
{
    private int              sizeIndex, size, rotate, maxPadding, paddingSize;
    private bool             scaleX,    scaleY;
    private Color            bgColor;
    private string           xaml;
    private FrameworkElement codeImage;
    private int              mLeft, mRight, mTop, mBottom;
    private string           exceptionMsg;
    private DispatcherTimer  timer;
    private int              selectedBackgroundIndex, backgroundRotate;

    private readonly Dictionary<int, int> sizeItems = new() {
        {
            1, 16
        }, {
            2, 32
        }, {
            3, 64
        }, {
            4, 128
        }, {
            5, 256
        }, {
            6, 512
        }, {
            7, -1
        }
    };

    /// <summary>
    /// 构造
    /// </summary>
    public ExportProperty(Color bgColor, ImageSource imageSource)
    {
        this.ImageSource     = imageSource;
        Backgrounds          = BackgroundManager.Instance.Backgrounds;
        BackgroundColors     = BackgroundManager.Instance.BackgroundColors;
        this.BackgroundColor = bgColor;
        SelectedSizeIndex    = 5;
        timer = new DispatcherTimer {
            Interval = TimeSpan.FromMilliseconds(1000), IsEnabled = false
        };
        timer.Tick += TimerTick;
    }


#region Methods...

    private void TimerTick(object sender, EventArgs e)
    {
        timer.Stop();
        try
        {
            CodeImage    = ImageUtility.XamlToControl(xaml, true);
            ErrorMessage = string.Empty;
        }
        catch (Exception ex)
        {
            ErrorMessage = ex.Message;
            CodeImage    = null;
        }
    }

    /// <summary>
    /// 重置
    /// </summary>
    /// <param name="bColor">背景颜色</param>
    public void Reset(Color bColor)
    {
        SelectedSizeIndex       = 5;
        this.BackgroundColor    = bColor;
        mLeft                   = mTop = mRight = mBottom = 0;
        rotate                  = 0;
        scaleX                  = false;
        scaleY                  = false;
        selectedBackgroundIndex = 0;
        backgroundRotate        = 0;
        SizeChanged();
        this.OnPropertyChanged("");
    }

#endregion

    /// <summary>
    /// 获取 图像源
    /// </summary>
    public ImageSource ImageSource { get; }

    /// <summary>
    /// 图像 XAML 内容
    /// </summary>
    public string Xaml {
        get => xaml;
        set =>
            this.SetValue(ref xaml, value, nameof(Xaml), () => {
                timer.Stop();
                timer.Start();
            });
    }

    /// <summary>
    /// 错误信息
    /// </summary>
    public string ErrorMessage {
        get => exceptionMsg;
        private set =>
            SetValue(ref exceptionMsg, value, nameof(ErrorMessage), () => {
                this.OnPropertyChanged(nameof(HaveError));
            });
    }

    /// <summary>
    /// 是否有错误
    /// </summary>
    public bool HaveError => string.IsNullOrEmpty(exceptionMsg) == false;

    /// <summary>
    /// 代码模式图像内容控件
    /// </summary>
    public FrameworkElement CodeImage {
        get => codeImage;
        private set => SetValue(ref codeImage, value, nameof(CodeImage));
    }

    /// <summary>
    /// 可使用的图像背景
    /// </summary>
    public IReadOnlyList<Geometry> Backgrounds { get; }

    /// <summary>
    /// 默认背景颜色列表
    /// </summary>
    public IReadOnlyList<Color> BackgroundColors { get; }

    /// <summary>
    /// 选中的图像大小索引
    /// </summary>
    public int SelectedSizeIndex {
        get => sizeIndex;
        set =>
            this.SetValue(ref sizeIndex, value, nameof(SelectedSizeIndex), () => {
                if (value != sizeItems.Count)
                {
                    Size = sizeItems[value];
                }
            });
    }

    /// <summary>
    /// 获取或设置选中的背景索引
    /// </summary>
    public int SelectedBackgroundIndex {
        get => selectedBackgroundIndex;
        set =>
            SetValue(ref selectedBackgroundIndex, value, nameof(SelectedBackgroundIndex),
                () => {
                    OnPropertyChanged(nameof(SelectedBackground));
                    OnPropertyChanged(nameof(CanSetBackground));
                    BackgroundRotate = 0;
                });
    }

    /// <summary>
    /// 选中的图像背景索引
    /// </summary>
    public Geometry SelectedBackground => Backgrounds[selectedBackgroundIndex];

    /// <summary>
    /// 是否允许设计背景
    /// </summary>
    public Visibility CanSetBackground => selectedBackgroundIndex != 0 ? Visibility.Visible : Visibility.Collapsed;

    /// <summary>
    /// 图像大小
    /// </summary>
    public int Size {
        get => size;
        set {
            if (value > 9999)
            {
                value = 9999;
            }

            this.SetValue(ref size, value, nameof(Size), SizeChanged);
        }
    }

    private void SizeChanged()
    {
        MaxPadding  = (int)(size / 3.14);
        PaddingSize = MaxPadding * 3 / 4;

        int index = sizeItems.Count;
        foreach (var s in sizeItems)
        {
            if (s.Value == size)
            {
                index = s.Key;
            }
        }

        SelectedSizeIndex = index;
    }

    /// <summary>
    /// 最大内边距
    /// </summary>
    public int MaxPadding {
        get => maxPadding;
        set => this.SetValue(ref maxPadding, value, nameof(MaxPadding));
    }

    /// <summary>
    /// 图像内边距
    /// </summary>
    public int PaddingSize {
        get => paddingSize;
        set => this.SetValue(ref paddingSize, value, nameof(PaddingSize), () => OnPropertyChanged(nameof(Padding)));
    }

    /// <summary>
    /// 内边距
    /// </summary>
    public Thickness Padding => new(paddingSize);

    /// <summary>
    /// 外边距 - 左
    /// </summary>
    public int MarginLeft {
        get => mLeft;
        set => SetValue(ref mLeft, value, nameof(MarginLeft), () => OnPropertyChanged(nameof(Margin)));
    }

    /// <summary>
    /// 外边距 - 右
    /// </summary>
    public int MarginRight {
        get => mRight;
        set => SetValue(ref mRight, value, nameof(MarginRight), () => OnPropertyChanged(nameof(Margin)));
    }

    /// <summary>
    /// 外边距 - 上
    /// </summary>
    public int MarginTop {
        get => mTop;
        set => SetValue(ref mTop, value, nameof(MarginTop), () => OnPropertyChanged(nameof(Margin)));
    }

    /// <summary>
    /// 外边距 - 下
    /// </summary>
    public int MarginBottom {
        get => mBottom;
        set => SetValue(ref mBottom, value, nameof(MarginBottom), () => OnPropertyChanged(nameof(Margin)));
    }

    /// <summary>
    /// 外边距
    /// </summary>
    public Thickness Margin => new(mLeft, mTop, mRight, mBottom);

    /// <summary>
    /// 图像旋转角度
    /// </summary>
    public int Rotate {
        get => rotate;
        set => this.SetValue(ref rotate, value, nameof(Rotate));
    }

    /// <summary>
    /// 图像 X 轴翻转
    /// </summary>
    public bool ScaleX {
        get => scaleX;
        set => this.SetValue(ref scaleX, value, nameof(ScaleX), () => OnPropertyChanged(nameof(ScaleXValue)));
    }

    /// <summary>
    /// 图像 翻转 X 值
    /// </summary>
    public int ScaleXValue => scaleX ? -1 : 1;

    /// <summary>
    /// 图像 Y 轴翻转
    /// </summary>
    public bool ScaleY {
        get => scaleY;
        set => this.SetValue(ref scaleY, value, nameof(ScaleY), () => OnPropertyChanged(nameof(ScaleYValue)));
    }

    /// <summary>
    /// 图像 翻转 Y 值
    /// </summary>
    public int ScaleYValue => scaleY ? -1 : 1;

    /// <summary>
    /// 背景使用的颜色
    /// </summary>
    public Color BackgroundColor {
        get => bgColor;
        set => this.SetValue(ref bgColor, value, nameof(BackgroundColor));
    }

    /// <summary>
    /// 背景旋转角度
    /// </summary>
    public int BackgroundRotate {
        get => backgroundRotate;
        set => SetValue(ref backgroundRotate, value, nameof(BackgroundRotate));
    }
}